package com.kexio.security.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.kexio.core.data.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;

/**
 * 用户权限直接关联实体
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user_permission")
@Schema(description = "用户权限直接关联实体")
public class UserPermission extends BaseEntity {

    /**
     * 用户ID
     */
    @NotNull(message = "用户ID不能为空")
    @TableField("user_id")
    @Schema(description = "用户ID", example = "1")
    private Long userId;

    /**
     * 权限ID
     */
    @NotNull(message = "权限ID不能为空")
    @TableField("permission_id")
    @Schema(description = "权限ID", example = "1")
    private Long permissionId;

    /**
     * 是否授予权限（true:授予, false:拒绝）
     */
    @TableField("is_granted")
    @Schema(description = "是否授予权限", example = "true")
    private Boolean isGranted = true;

    /**
     * 优先级（用于解决权限冲突，数字越大优先级越高）
     */
    @TableField("priority")
    @Schema(description = "优先级", example = "10")
    private Integer priority = 0;

    /**
     * 生效时间
     */
    @TableField("start_time")
    @Schema(description = "生效时间", example = "2024-01-01 00:00:00")
    private LocalDateTime startTime;

    /**
     * 失效时间
     */
    @TableField("end_time")
    @Schema(description = "失效时间", example = "2024-12-31 23:59:59")
    private LocalDateTime endTime;

    /**
     * 租户ID
     */
    @TableField("tenant_id")
    @Schema(description = "租户ID", example = "1")
    private Long tenantId;

    // =========================== 便利方法 ===========================

    /**
     * 检查权限关联是否有效
     * @return 是否有效
     */
    public boolean isValid() {
        LocalDateTime now = LocalDateTime.now();
        return (startTime == null || !now.isBefore(startTime)) 
            && (endTime == null || !now.isAfter(endTime));
    }

    /**
     * 检查权限关联是否已过期
     * @return 是否已过期
     */
    public boolean isExpired() {
        if (endTime == null) {
            return false;
        }
        return LocalDateTime.now().isAfter(endTime);
    }

    /**
     * 检查权限关联是否还未生效
     * @return 是否还未生效
     */
    public boolean isPending() {
        if (startTime == null) {
            return false;
        }
        return LocalDateTime.now().isBefore(startTime);
    }

    /**
     * 检查是否被明确拒绝权限
     * @return 是否被拒绝
     */
    public boolean isDenied() {
        return Boolean.FALSE.equals(isGranted) && isValid();
    }

    /**
     * 检查是否被明确授予权限
     * @return 是否被授予
     */
    public boolean isGranted() {
        return Boolean.TRUE.equals(isGranted) && isValid();
    }

    /**
     * 设置永久授权
     */
    public void setPermanentGrant() {
        this.isGranted = true;
        this.startTime = null;
        this.endTime = null;
    }

    /**
     * 设置临时授权
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param priority 优先级
     */
    public void setTemporaryGrant(LocalDateTime startTime, LocalDateTime endTime, Integer priority) {
        this.isGranted = true;
        this.startTime = startTime;
        this.endTime = endTime;
        this.priority = priority != null ? priority : 0;
    }

    /**
     * 设置永久拒绝
     */
    public void setPermanentDeny() {
        this.isGranted = false;
        this.startTime = null;
        this.endTime = null;
    }

    /**
     * 拒绝权限
     * @param priority 优先级
     */
    public void deny(Integer priority) {
        this.isGranted = false;
        this.priority = priority != null ? priority : 0;
    }

    /**
     * 授予权限
     * @param priority 优先级
     */
    public void grant(Integer priority) {
        this.isGranted = true;
        this.priority = priority != null ? priority : 0;
    }

    /**
     * 比较优先级
     * @param other 其他用户权限
     * @return 优先级比较结果 (正数：当前优先级更高，负数：当前优先级更低，0：相等)
     */
    public int comparePriority(UserPermission other) {
        if (other == null) {
            return 1;
        }
        int thisPriority = this.priority != null ? this.priority : 0;
        int otherPriority = other.priority != null ? other.priority : 0;
        return Integer.compare(thisPriority, otherPriority);
    }
}
